package sicnu.cs.ich.user.rest;

import org.springframework.beans.BeanUtils;
import org.springframework.web.multipart.MultipartFile;
import sicnu.cs.ich.api.common.Constants;
import sicnu.cs.ich.api.common.ResultInfo;
import sicnu.cs.ich.api.common.enums.FileEnum;
import sicnu.cs.ich.api.domain.entity.Certification;
import sicnu.cs.ich.api.domain.form.UserInfoForm;
import sicnu.cs.ich.common.services.IFileUploadService;

import static sicnu.cs.ich.common.util.FileUtils.*;

import sicnu.cs.ich.common.util.ResultInfoUtil;
import sicnu.cs.ich.security.domain.entity.User;
import sicnu.cs.ich.user.service.ICertService;
import sicnu.cs.ich.user.service.IRegionService;
import sicnu.cs.ich.security.service.IUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
import sicnu.cs.ich.api.domain.entity.UserInfo;
import sicnu.cs.ich.api.domain.form.CertificateUserForm;
import sicnu.cs.ich.common.services.ISendMailService;
import sicnu.cs.ich.common.services.impl.RedisService;


import javax.validation.Valid;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;

import static sicnu.cs.ich.security.util.SecurityUtil.getCurrentUserId;
import static sicnu.cs.ich.security.util.ValidateUtils.*;


/**
 * @author 沈洋 邮箱:1845973183@qq.com
 * @create 2021/10/26-13:09
 **/
@Slf4j
@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
@Api(tags = {"用户模块"})
public class UserResource {
    private final IUserService userService;
    private final IRegionService regionService;
    private final RedisService redisService;
    private final ISendMailService sendMailService;
    private final PasswordEncoder passwordEncoder;
    private final ICertService certService;
    private final IFileUploadService fileUploadService;
    private final static String NEW_PASSWORD = "newPassword";
    private final static String OLD_PASSWORD = "oldPassword";

    @ApiOperation(value = "发送邮箱验证码(邮箱是可选项,默认是发送给登录账户的邮箱")
    @GetMapping("/emailCode")
    public ResultInfo<Void> sendLoginByEmailCode(@RequestParam(required = false) String email) {
        if (email == null) {
            User user = userService.findUser(getCurrentUserId());
            email = user.getEmail();
        } else if (!isValidEmail(email)) {
            return ResultInfoUtil.buildError("邮箱格式错误");
        }
        // 发送验证码邮件(生成6位随机数)
        String code = createValidateCode();
        // 保存验证码
        redisService.cacheValue(Constants.REDIS_EMAIL_CODE + code, email, 60 * 5);
        sendMailService.sendValidateCodeEmail(email, code);
        return ResultInfoUtil.buildSuccess();
    }

    @ApiOperation(value = "更改邮箱")
    @GetMapping("/resetEmail/{code}")
    public ResultInfo<String> resetEmail(@PathVariable String code) {
        // 校验验证码是否存在，并取出邮箱
        String email = (String) redisService.getValue(Constants.REDIS_EMAIL_CODE + code);
        if (StringUtils.isBlank(email)) {
            return ResultInfoUtil.buildError("验证码错误或已过期");
        }
        // 先验证邮箱是否可用
        if (userService.isEmailExisted(email)) {
            return ResultInfoUtil.buildError("邮箱已认证");
        }
        // 修改密码
        if (userService.updateEmail(getCurrentUserId(), email)) {
            return ResultInfoUtil.buildSuccess();
        } else {
            return ResultInfoUtil.buildError();
        }
    }

    @ApiOperation("上传头像")
    @PostMapping("/avaterUrl")
    public ResultInfo<String> uploadAvater(@RequestParam MultipartFile file) throws IOException {
        // 校验文件合法性
        // 文件是否为空、是否为图片、
        if (!isImage(file)) {
            return ResultInfoUtil.buildError("文件不合法");
        }
        // 验证文件大小
        if (file.getSize() > mbTob(3)) {
            return ResultInfoUtil.buildError("文件大小不能超过3MB");
        }
        // todo 不删除图片，直接覆盖
        // 上传图片，删除旧图片
        String filePath = fileUploadService.uploadFile((FileInputStream) file.getInputStream()
                , FileEnum.USER_AVATER, file.getOriginalFilename());
        String oldPath = userService.findUserInfo(getCurrentUserId()).getAvaterUrl();
        if (StringUtils.isNotBlank(oldPath)) {
            // 删除文件
            fileUploadService.deleteFile(oldPath);
        }
        // 更新头像
        UserInfo user = UserInfo.builder()
                .userId(getCurrentUserId())
                .avaterUrl(filePath)
                .build();
        if (userService.updateUserInfo(user)) {
            return ResultInfoUtil.buildSuccessWithStr(filePath);
        }
        return ResultInfoUtil.buildError();
    }

    @ApiOperation("修改个人信息")
    @PutMapping("/userinfo")
    public ResultInfo<Map<String, Object>> updateUserInfo(@Valid @RequestBody UserInfoForm userForm) throws InvocationTargetException, IllegalAccessException {
        //修改昵称、性别、生日、个人介绍、签名、地区、地址
        UserInfo userInfo = new UserInfo();
        BeanUtils.copyProperties(userForm, userInfo);
        userInfo.setUserId(getCurrentUserId());
        if (userInfo.getRegionId() != null && !regionService.isExists(userInfo.getRegionId())) {
            userInfo.setRegionId(null);
        }
        userService.updateUserInfo(userInfo);
        UserInfo curUser = userService.findUserInfo(getCurrentUserId());
        // 身份证号脱敏
        String idNumber = userInfo.getIdNumber();
        if (StringUtils.isNotBlank(idNumber) && idNumber.length() == 18) {
            userInfo.setIdNumber(idNumber.substring(0, 4)
                    + "*".repeat(10) + idNumber.substring(14));
        }
        return ResultInfoUtil.buildSuccess(Map.of("userinfo", curUser));
    }

    @ApiOperation(value = "修改密码", notes = "参数：newPassword、oldPassword")
    @PutMapping("/password")
    public ResultInfo<Void> updatePassword(@RequestBody Map<String, String> param) {
        if (!isValidStrParams(param, NEW_PASSWORD, OLD_PASSWORD)) {
            return ResultInfoUtil.buildError();
        }
        Integer userid = getCurrentUserId();
        String password = userService.findPassword(userid);
        ResultInfo<Void> result = null;
        if (passwordEncoder.matches(param.get(OLD_PASSWORD), password)) {
            if (userService.resetPassword(userid, param.get(NEW_PASSWORD))) {
                result = ResultInfoUtil.buildSuccess("修改成功");
            } else {
                result = ResultInfoUtil.buildError("密码不合法");
            }
        } else {
            result = ResultInfoUtil.buildError("密码错误");
        }
        return result;
    }

    @ApiOperation("获取用户信息")
    @GetMapping("/userinfo")
    public ResultInfo<Map<String, Object>> getUserinfo() {
        UserInfo userInfo = userService.findUserInfo(getCurrentUserId());
        // 身份证号脱敏
        String idNumber = userInfo.getIdNumber();
        if (StringUtils.isNotBlank(idNumber) && idNumber.length() == 18) {
            userInfo.setIdNumber(idNumber.substring(0, 4)
                    + "*".repeat(10) + idNumber.substring(14));
        }
        User user = userService.findUser(getCurrentUserId());
        return ResultInfoUtil.buildSuccess(Map.of("user", user, "userinfo", userInfo));
    }

    @ApiOperation("用户认证信息")
    @GetMapping("/cert")
    public ResultInfo<List<Certification>> certInfo() {
        // 实名认证状态
        // 机构认证状态
        var certs = certService.findAllCert(getCurrentUserId());
        return ResultInfoUtil.buildSuccess(certs);
    }

    @ApiOperation("机构认证")
    @PostMapping("/certificate")
    public ResultInfo<Void> certificate() {
        return null;
    }

    @ApiOperation("用户实名认证")
    @PostMapping("/certificateUser")
    public ResultInfo<Void> certificateUser(@Valid CertificateUserForm userForm) throws IOException {
        // 验证文件格式
        var fileList = isImage(userForm.getFrontImage(),userForm.getBackImage());
        if (fileList.size()<2) return ResultInfoUtil.buildError("文件不合法");
        // 验证文件大小
        if (userForm.getBackImage().getSize() > mbTob(3)
                || userForm.getFrontImage().getSize() > mbTob(3)) {
            return ResultInfoUtil.buildError("文件大小不能超过3MB");
        }
        return certService.certUser(userForm);
    }

    @PutMapping("/mobile")
    @ApiOperation("修改手机号")
    public ResultInfo<Void> updateMobile(@RequestParam String mobile) {
        if (userService.isMobileExisted(mobile)) {
            return ResultInfoUtil.buildError("手机号已绑定账号");
        }
        boolean isUpdate = userService.updateUser(User.builder().id(getCurrentUserId())
                .mobile(mobile).build());
        return isUpdate ? ResultInfoUtil.buildSuccess()
                : ResultInfoUtil.buildError();
    }
}
